package com.gitee.apanlh.util.thread;

import com.gitee.apanlh.util.cache.local.Cache;
import com.gitee.apanlh.util.cache.local.CacheUtils;
import com.gitee.apanlh.util.func.FuncLock;
import com.gitee.apanlh.util.func.FuncLockResult;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import java.util.concurrent.locks.StampedLock;

/**
 * 	锁执行器类(自动获取锁及释放锁)
 * 	<br>此类封装了一些锁操作，用于在特定范围内获取锁，可以在锁的保护范围内执行特定的操作，并确保在退出该范围时释放锁
 * 	<p>
 * 	例如：
 * 	<pre>
 * 		{@code
 * 		LockExecutor lockExecutor = new LockExecutor();
 *      lockExecutor.writeLock(() -> {
 *   	// 执行需要写锁保护的操作
 *   	});
 * 		}
 *
 * 	</pre>
 * 	或者
 * 	<pre>
 * 	{@code
 * 		LockExecutor lockExecutor = new LockExecutor();
 * 		String result = lockExecutor.readLock(() -> {
 * 		// 执行需要读锁保护的操作，并返回结果
 * 		return "x";
 * 		});
 * 	}
 * 	</pre>
 *
 * 	@author Pan
 */
public class LockExecutor {
	
	/** 锁 */
	private Lock lock;
	/** 读写锁 */
	private ReentrantReadWriteLock reentrantReadWriteLock;
	/** 不可重入读写锁 */
	private StampedLock stampedLock;
	/** 锁缓存 */
	private static final Cache<String, LockExecutor> CACHE = CacheUtils.cache();
	
	/**
	 * 	默认构造函数
	 * 	<br>重入锁
	 * 	
	 * 	@author Pan
	 */
	public LockExecutor() {
		this(new ReentrantLock());
	}
	
	/**	
	 * 	构造函数-自定义锁
	 * 	
	 * 	@author Pan
	 * 	@param  lock 锁
	 */
	public LockExecutor(Lock lock) {
		this.lock = lock;
	}
	
	/**	
	 * 	构造函数-读写锁
	 * 	
	 * 	@author Pan
	 * 	@param  lock 锁
	 */
	public LockExecutor(ReentrantReadWriteLock lock) {
		this.reentrantReadWriteLock = lock;
	}
	
	/**	
	 * 	构造函数-不可重入读写锁
	 * 	
	 * 	@author Pan
	 * 	@param  lock 锁
	 */
	public LockExecutor(StampedLock lock) {
		this.stampedLock = lock;
	}
	
	/**	
	 * 	锁
	 * 	
	 * 	@author Pan
	 * 	@param 	doLock	锁操作
	 */
	public void lock(FuncLock doLock) {
		lock.lock();
		try {
			doLock.lock();
		} finally {
			lock.unlock();
		}
	}
	
	/**	
	 * 	锁
	 * 	<br>可自定义返回值
	 * 	<br>避免在循环中使用拉姆达表达式在用此锁会降低效率
	 * 	<br>例如：
	 * 
	 * 	@author Pan
	 *	@param  <V>		泛型
	 * 	@param 	doLock	锁操作
	 * 	@return V
	 */
	public <V> V lock(FuncLockResult<V> doLock) {
		lock.lock();
		try {
			return doLock.lock();
		} finally {
			lock.unlock();
		}
	}
	
	/**	
	 * 	写锁
	 * 	<br>注意:必须存在读写锁
	 * 	<br>动态使用ReentrantReadWriteLock或StampedLock
	 * 	
	 * 	@author Pan
	 * 	@param 	doLock	锁操作
	 */
	public void writeLock(FuncLock doLock) {
		if (stampedLock == null) {
			this.reentrantReadWriteLock.writeLock().lock();
			try {
				doLock.lock();
			} finally {
				this.reentrantReadWriteLock.writeLock().unlock();
			}
			return ;
		}
		
		long writeLock = stampedLock.writeLock();
		try {
			doLock.lock();
		} finally {
			stampedLock.unlockWrite(writeLock);
		}
	}
	
	/**	
	 * 	写锁
	 * 	<br>可自定义返回值
	 * 	<br>注意:必须存在读写锁
	 * 	<br>动态使用ReentrantReadWriteLock或StampedLock
	 * 
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param 	doLock	锁操作
	 * 	@return	V
	 */
	public <V> V writeLock(FuncLockResult<V> doLock) {
		if (stampedLock == null) {
			this.reentrantReadWriteLock.writeLock().lock();
			try {
				return doLock.lock();
			} finally {
				this.reentrantReadWriteLock.writeLock().unlock();
			}
		}
		
		long writeLock = stampedLock.writeLock();
		try {
			return doLock.lock();
		} finally {
			stampedLock.unlockWrite(writeLock);
		}
	}
	
	/**	
	 * 	读锁
	 * 	<br>注意:必须存在读写锁
	 * 	<br>动态使用ReentrantReadWriteLock或StampedLock
	 * 
	 * 	@author Pan
	 * 	@param 	doLock	锁操作
	 */
	public void readLock(FuncLock doLock) {
		if (stampedLock == null) {
			reentrantReadWriteLock.readLock().lock();
			try {
				doLock.lock();
			} finally {
				reentrantReadWriteLock.readLock().unlock();
			}
			return ;
		} 
		
		long readLock = stampedLock.readLock();
		try {
			doLock.lock();
		} finally {
			this.stampedLock.unlock(readLock);
		}
	}
	
	/**	
	 * 	读锁
	 * 	<br>可自定义返回值
	 * 	<br>注意:必须存在读写锁
	 * 	<br>动态使用ReentrantReadWriteLock或StampedLock
	 * 
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param 	doLock	锁操作
	 * 	@return V
	 */
	public <V> V readLock(FuncLockResult<V> doLock) {
		if (stampedLock == null) {
			this.reentrantReadWriteLock.readLock().lock();
			try {
				return doLock.lock();
			} finally {
				this.reentrantReadWriteLock.readLock().unlock();
			}
		} 
		
		long readLock = this.stampedLock.readLock();
		try {
			return doLock.lock();
		} finally {
			this.stampedLock.unlock(readLock);
		}
	}
	
	/**	
	 * 	获取锁对象
	 * 	
	 * 	@author Pan
	 * 	@return	Lock
	 */
	public Lock getLock() {
		return this.lock;
	}

	/**	
	 * 	获取读写锁对象
	 * 	
	 * 	@author Pan
	 * 	@return ReentrantReadWriteLock
	 */
	public ReentrantReadWriteLock getReentrantReadWriteLock() {
		return this.reentrantReadWriteLock;
	}

	/**	
	 * 	获取读写锁对象
	 * 	
	 * 	@author Pan
	 * 	@return StampedLock
	 */
	public StampedLock getStampedLock() {
		return this.stampedLock;
	}

	/**	
	 * 	获取写锁对象
	 * 	
	 * 	@author Pan
	 * 	@return	Lock
	 */
	public WriteLock getWriteLock() {
		return this.reentrantReadWriteLock == null ? null : this.reentrantReadWriteLock.writeLock();
	}
	
	/**	
	 * 	获取读锁对象
	 * 	
	 * 	@author Pan
	 * 	@return	Lock
	 */
	public ReadLock getReadLock() {
		return this.reentrantReadWriteLock == null ? null : this.reentrantReadWriteLock.readLock();
	}
	
	/**	
	 * 	获取写锁对象
	 * 	<br>返回的 Lock 不支持 Condition方法 Lock.newCondition() 引发 UnsupportedOperationException
	 * 	
	 * 	@author Pan
	 * 	@return	Lock
	 */
	public Lock getWriteLockFromStamped() {
		return this.stampedLock == null ? null : this.stampedLock.asWriteLock();
	}
	
	/**	
	 * 	获取读锁对象
	 * 	<br>返回的 Lock 不支持 Condition方法 Lock.newCondition() 引发 UnsupportedOperationException
	 * 	
	 * 	@author Pan
	 * 	@return	Lock
	 */
	public Lock getReadLockFromStamped() {
		return  this.stampedLock == null ? null : this.stampedLock.asReadLock();
	}
	
	/**	
	 * 	创建锁执行器，默认重入锁
	 * 	
	 * 	@author Pan
	 * 	@return	LockExecutor
	 */
	public static LockExecutor create() {
		return new LockExecutor();
	}	
	
	/**	
	 * 	创建锁执行器
	 * 	<br>相关实现Lock锁类
	 * 	
	 * 	@author Pan
	 * 	@param 	lock	Lock接口
	 * 	@return	LockExecutor
	 */
	public static LockExecutor create(Lock lock) {
		return new LockExecutor(lock);
	}

	/**	
	 * 	创建锁执行器
	 * 	<br>读写锁
	 * 	
	 * 	@author Pan
	 * 	@return	LockExecutor
	 */
	public static LockExecutor createReadWriteLock() {
		return new LockExecutor(new ReentrantReadWriteLock());
	}
	
	/**	
	 * 	创建锁执行器
	 * 	<br>不可重入读写锁
	 * 	
	 * 	@author Pan
	 * 	@return	LockExecutor
	 */
	public static LockExecutor createStampedLock() {
		return new LockExecutor(new StampedLock());
	}
	
	/**	
	 * 	使用锁保护某一个方法块
	 * 	<br>默认使用重入锁
	 * 	
	 * 	@author Pan
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLock 	      执行函数
	 */
	public static void executeLock(String customLockName, FuncLock funcLock) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::create);
		Lock lock = lockExecutor.getLock();
		lock.lock();
		try {
			funcLock.lock();
		} finally {
			lock.unlock();
		}
	}
	
	/**	
	 * 	使用锁保护某一个方法块
	 * 	<br>默认使用重入锁
	 * 	<br>可自定义返回指定值
	 * 	
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLockResult 执行函数
	 * 	@return V
	 */
	public static <V> V executeLock(String customLockName, FuncLockResult<V> funcLockResult) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::create);
		Lock lock = lockExecutor.getLock();
		lock.lock();
		try {
			return funcLockResult.lock();
		} finally {
			lock.unlock();
		}
	}
	
	/**	
	 * 	使用读锁保护某一个方法块
	 * 	<br>默认使用重入读写锁
	 * 	
	 * 	@author Pan
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLock 	      执行函数
	 */
	public static void executeReadLockFormReadWrite(String customLockName, FuncLock funcLock) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		ReadLock readLock = lockExecutor.getReadLock();
		readLock.lock();
		try {
			funcLock.lock();
		} finally {
			readLock.unlock();
		}
	}
	
	/**	
	 * 	使用读锁保护某一个方法块
	 * 	<br>默认使用重入读写锁
	 * 	<br>可自定义返回指定值
	 * 	
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLockResult 执行函数
	 * 	@return V
	 */
	public static <V> V executeReadLockFormReadWrite(String customLockName, FuncLockResult<V> funcLockResult) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		ReadLock readLock = lockExecutor.getReadLock();
		readLock.lock();
		try {
			return funcLockResult.lock();
		} finally {
			readLock.unlock();
		}
	}
	
	/**	
	 * 	使用读锁保护某一个方法块
	 * 	<br>默认使用不可重入读写锁
	 * 	
	 * 	@author Pan
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLock 	      执行函数
	 */
	public static void executeReadLockFormStamped(String customLockName, FuncLock funcLock) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		Lock readLock = lockExecutor.getReadLockFromStamped();
		readLock.lock();
		try {
			funcLock.lock();
		} finally {
			readLock.unlock();
		}
	}
	
	/**	
	 * 	使用读锁保护某一个方法块
	 * 	<br>默认使用不可重入读写锁
	 * 	<br>可自定义返回指定值
	 * 	
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLockResult 执行函数
	 * 	@return V
	 */
	public static <V> V executeReadLockFormStamped(String customLockName, FuncLockResult<V> funcLockResult) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		Lock readLock = lockExecutor.getReadLockFromStamped();
		readLock.lock();
		try {
			return funcLockResult.lock();
		} finally {
			readLock.unlock();
		}
	}
	
	/**	
	 * 	使用写锁保护某一个方法块
	 * 	<br>默认使用重入读写锁
	 * 	
	 * 	@author Pan
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLock 	      执行函数
	 */
	public static void executeWriteLockFormReadWrite(String customLockName, FuncLock funcLock) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		WriteLock writeLock = lockExecutor.getWriteLock();
		writeLock.lock();
		try {
			funcLock.lock();
		} finally {
			writeLock.unlock();
		}
	}
	
	/**	
	 * 	使用写锁保护某一个方法块
	 * 	<br>默认使用重入读写锁
	 * 	<br>可自定义返回指定值
	 * 	
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLockResult 执行函数
	 * 	@return V
	 */
	public static <V> V executeWriteLockFormReadWrite(String customLockName, FuncLockResult<V> funcLockResult) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		WriteLock writeLock = lockExecutor.getWriteLock();
		writeLock.lock();
		try {
			return funcLockResult.lock();
		} finally {
			writeLock.unlock();
		}
	}
	
	/**	
	 * 	使用写锁保护某一个方法块
	 * 	<br>默认使用不可重入读写锁
	 * 	
	 * 	@author Pan
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLock 	      执行函数
	 */
	public static void executeWriteLockFormStamped(String customLockName, FuncLock funcLock) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		Lock writeLock = lockExecutor.getWriteLockFromStamped();
		writeLock.lock();
		try {
			funcLock.lock();
		} finally {
			writeLock.unlock();
		}
	}
	
	/**	
	 * 	使用写锁保护某一个方法块
	 * 	<br>默认使用不可重入读写锁
	 * 	<br>可自定义返回指定值
	 * 	
	 * 	@author Pan
	 * 	@param  <V>		泛型
	 * 	@param  customLockName 自定义锁名称不可重复
	 * 	@param 	funcLockResult 执行函数
	 * 	@return V
	 */
	public static <V> V executeWriteLockFormStamped(String customLockName, FuncLockResult<V> funcLockResult) {
		LockExecutor lockExecutor = CACHE.get(customLockName, LockExecutor::createReadWriteLock);
		Lock writeLock = lockExecutor.getWriteLockFromStamped();
		writeLock.lock();
		try {
			return funcLockResult.lock();
		} finally {
			writeLock.unlock();
		}
	}
}
